home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Gold Collection / Software Vault - The Gold Collection (American Databankers) (1993).ISO / cdr22 / ctest259.zip / CCNEW.ASM < prev    next >
Assembly Source File  |  1993-06-07  |  41KB  |  740 lines

  1.              PAGE    ,120
  2.  
  3.             .386p                        ; 80386 code will be used
  4.             .387                         ; need coprocessor, too
  5.  
  6. JMPS        EQU     <JMP SHORT>          ; declare jumps as short
  7. JES         EQU     <JE  SHORT>          ;  since near jumps (+/- 32K)
  8. JBS         EQU     <JB  SHORT>          ;   are default in 386 mode
  9. JNZS        EQU     <JNZ SHORT>          ;    and these cannot execute
  10. JCS         EQU     <JC  SHORT>          ;     on the older CPUs
  11. JZS         EQU     <JZ  SHORT>
  12. JNES        EQU     <JNE SHORT>
  13. JAES        EQU     <JAE SHORT>
  14. JBES        EQU     <JBE SHORT>
  15. JAS         EQU     <JA  SHORT>
  16.  
  17. cpu_i8088   EQU     1
  18. cpu_i8086   EQU     2
  19. cpu_V20     EQU     3
  20. cpu_V30     EQU     4
  21. cpu_i188    EQU     5
  22. cpu_i186    EQU     6
  23. cpu_i286    EQU     7
  24. cpu_i386    EQU     8
  25. cpu_i386sx  EQU     9
  26. cpu_ct38600 EQU     10
  27. cpu_ct38600sx   EQU     11
  28. cpu_486dlc  EQU     12
  29. cpu_486slc  EQU     13
  30. cpu_RapidCAD EQU     14
  31. cpu_i486    EQU     15
  32. cpu_i486SX  EQU     16
  33. cpu_pentium EQU     17
  34.  
  35. ndp_NoCopro EQU     0
  36. ndp_Emul    EQU     1
  37. ndp_i8087   EQU     2
  38. ndp_i80C187 EQU     3
  39. ndp_i80287  EQU     4
  40. ndp_i287XL  EQU     5
  41. ndp_i387    EQU     6
  42. ndp_i387sx  EQU     7
  43. ndp_2C87    EQU     8
  44. ndp_3C87    EQU    10
  45. ndp_3C87sx  EQU    11
  46. ndp_82S87   EQU    12
  47. ndp_83D87   EQU    14
  48. ndp_83S87   EQU    15
  49. ndp_83C87   EQU    16
  50. ndp_83C87s  EQU    17
  51. ndp_38700   EQU    18
  52. ndp_38700sx EQU    19
  53. ndp_i387DX  EQU    20
  54. ndp_RapidCAD EQU   21
  55. ndp_i486    EQU    22
  56. ndp_82S87p  EQU    23
  57. ndp_387plus EQU    25
  58. ndp_83S87p  EQU    26
  59. ndp_emc87   EQU    27
  60. ndp_pentium EQU    28
  61.  
  62.  
  63. STRT_TIM    MACRO
  64.             MOV     AL, 0B4h             ; timer 2 is
  65.             OUT     43h, AL              ;  programmed as a rate generator
  66.             XOR     AL, AL               ; load zero
  67.             OUT     42h, AL              ; reset
  68.             OUT     42h, AL              ;  timer 2
  69.             ENDM
  70.  
  71. STOP_TIM    MACRO
  72.             MOV     AL, 80h              ; timer 2
  73.             OUT     43h, AL              ;  immediately latched
  74.             IN      AL, 42h              ; read LSB
  75.             MOV     BL, AL               ; save LSB
  76.             IN      AL, 42h              ; read MSB
  77.             MOV     BH, AL               ; save MSB
  78.             NEG     BX                   ; negate for timer count
  79.             ENDM
  80.  
  81.  
  82.  
  83. CODE        SEGMENT BYTE USE16 PUBLIC 'CODE'
  84.  
  85.             ASSUME  CS:CODE
  86.  
  87.             PUBLIC  SpeedTest
  88.  
  89.                                          ; declare parameters
  90.  
  91. Debug_Flag  EQU     [BP+24]              ; <> 0, if debugging output desired
  92. Ext_Flag    EQU     [BP+22]              ; zero, if no extended memory
  93. EMS_Flag    EQU     [BP+20]              ; zero, if no expanded memory
  94. BufferPtr   EQU     [BP+16]              ; buffer for EMS u. EXT test
  95. EMS_Base    EQU     [BP+12]              ; address of EMS-frame
  96. ScreenPtr   EQU     [BP+8]               ; start address of video memory
  97. ResultPtr   EQU     [BP+4]               ; pointer to result struct
  98.  
  99.  
  100.                                          ; declare local variables
  101.  
  102. Stat        EQU     [BP-2]               ; mem for 80x87 status word
  103. Ctrl        EQU     [BP-4]               ; mem for 80x87 control word
  104. GDT         EQU     [BP-52]              ; mem for global descriptor table
  105. SystemStat  EQU     [BP-53]              ; mem for system status
  106. SaveCtrl    EQU     [BP-55]              ; original 80x87 control word
  107.  
  108.  
  109.                                          ; declare result record
  110. CPU_NDP_TYP EQU     [SI]
  111. AAMTime     EQU     [SI+2]
  112. MovEvenTime EQU     [SI+6]
  113. BIOSWrTime  EQU     [SI+8]
  114. MovByteTime EQU     [SI+10]
  115. MovEMSTime  EQU     [SI+12]
  116. MovExtTime  EQU     [SI+14]
  117. ScrFillTime EQU     [SI+16]
  118. Dummy2      EQU     [SI+18]
  119. i87Time     EQU     [SI+20]
  120. i287Time    EQU     [SI+22]
  121. MovDblTime  EQU     [SI+24]
  122.  
  123. SpeedTest   PROC    NEAR
  124.             PUSH    BP                   ; save caller's frame pointer
  125.             MOV     BP, SP               ; make new frame pointer
  126.             SUB     SP, 55               ; alloc mem for local variables
  127.             PUSH    DS                   ; save Turbo Pascal's data segment
  128.             PUSHF                        ; save original flag setting
  129.  
  130. $inittimer: CLI                          ; disable interrupts
  131.             CLD                          ; auto increment for string operations
  132.             IN      AL, 61h              ; port B - system control
  133.             MOV     [SystemStat], AL     ; save system status
  134.             AND     AL, 11111101b        ; clear speaker bit (disable speaker)
  135.             OR      AL, 1                ; turn on bit for timer 2 (enable it)
  136.             CMP     AL, [SystemStat]     ; system already configured correctly ?
  137.             JES     $aam                 ; no need to configure it
  138.             OUT     61h, AL              ; reconfigure system (tmr 2 on,spk off)
  139.  
  140. $aam:       CMP     WORD PTR Debug_Flag,0; debugging output desired ?
  141.             JNZS    $aam1                ; no
  142.             MOV     AH, 9                ; #9, print string
  143.             PUSH    CS                   ; load
  144.             POP     DS                   ;  address of
  145.             MOV     DX, OFFSET CS:$dbg2  ;   debugging message
  146.             INT     21h                  ; call DOS, print debugging message
  147.             JMPS    $aam1                ; skip message text
  148.  
  149. $dbg2       DB      'About to perform AAM speed test', 0Dh, 0Ah ,'$'
  150.  
  151. $aam1:      STRT_TIM                     ; start timer 2
  152.             REPT    200
  153.             AAM                          ; execute 200 AAMs
  154.             ENDM
  155.             STOP_TIM                     ; elapsed time of timer 2 in BX
  156.             LDS     SI, ResultPtr        ; pointer to result struct
  157.             MOV     [AAMTime], BX        ; save time for AAMs
  158.  
  159. $begin_test:CMP     WORD PTR Debug_Flag,0; debugging output desired ?
  160.             JNZS    $cpu_ndptst          ; nope
  161.             MOV     AH, 9                ; #9, print string
  162.             PUSH    CS                   ; load
  163.             POP     DS                   ;  address of
  164.             MOV     DX, OFFSET CS:$dbg1  ;   debugging message
  165.             INT     21h                  ; call DOS, print debugging message
  166.             JMPS    $cpu_ndptst          ; skip message text
  167. $dbg1       DB      'About to perform CPU and NDP test', 0Dh, 0Ah ,'$'
  168.  
  169. $cpu_ndptst:LDS     SI, ResultPtr        ; pointer to result struct
  170.             FNSTCW  [SaveCtrl]           ; save original NDP ctrl word
  171.             PUSH    SP                   ; test updating
  172.             POP     AX                   ;  of stackpointer
  173.             CMP     AX, SP               ; stackpointer updated before push ?
  174.             JES     $286_386             ; no, must be 286, 386 or 486
  175.             MOV     AX, 1                ; try to shift
  176.             MOV     CL, 33               ;  accu 33 times
  177.             SHL     AX, CL               ; shift count masked off ?
  178.             JNZS    $186_188             ; yes, must be 186 or 188
  179.             PUSHA                        ; PUSHA executed on 88/86 as JMP $+2
  180.             STC                          ; carry set if V20 or V30
  181.             JCS     $V20_V30             ; yes, must be V20 or V30
  182.             PUSHF                        ; save flags
  183.             POP     AX                   ; pop flags into AX
  184.             AND     AH, 00FH             ; clear bits 12-15 of flag register
  185.             PUSH    AX                   ; put new flags in stack
  186.             POPF                         ; pop into flag register
  187.             PUSHF                        ; put flags on stack
  188.             POP     AX                   ; get flags
  189.             AND     AH, 0F0H             ; test if all bits
  190.             CMP     AH, 0F0H             ;  in highest nibble set
  191.             JES     $88_86               ; all bits in highest nibble set
  192.             XOR     DL, DL               ; failed all tests, unknown CPU
  193.             JMPS    $copro_test          ; go and test NDP
  194. $88_86:     MOV     DL, cpu_i8088        ; else it's an 88 or 86
  195.             JMPS    $queue_test          ; decide wether 88 or 86
  196. $V20_V30:   POPA                         ; remove pushed bytes
  197.             MOV     DL, cpu_V20          ; it's an V20 or V30
  198.             JMPS    $queue_test          ; decide wether V20 or V30
  199. $186_188:   MOV     DL, cpu_i188         ; 188/186
  200. $queue_test:LEA     BX, [$patch]         ; load patch address into BX
  201.             MOV     BYTE PTR CS:[BX], 42h; preset with opcode for INC DX
  202.             MOV     AL, 90H              ; patch in a NOP (opcode 90h)
  203.             MOV     CL, 31               ; rotate register 31 times to use up
  204.             ROL     AH, CL               ;  time so prefetch queue can be filled
  205.             MOV     BYTE PTR CS:[BX], AL ; insert NOP at label $patch
  206.             NOP                          ; fill
  207.             NOP                          ;  prefetch
  208.             NOP                          ;   queue
  209.             NOP                          ;    with NOPs
  210. $patch:     INC     DX                   ; patched to NOP on i88, i188 and V20
  211. $copro_test:JMP     $ndp_test            ; check for coprocessor
  212. $286_386:   MOV     DL, cpu_i286         ; 286, 386 or 486
  213.             PUSH    7000h                ;  try to set
  214.             POPF                         ;   IOPL and NT fields
  215.             PUSHF                        ;    in bit 12-14
  216.             POP     AX                   ;     of flag register
  217.             TEST    AX, 7000h            ; bits cannot be set in 286 real mode
  218.             JZS     $copro_test          ; bits not set --> 286
  219.             INC     DX                   ; CPU is an 386 (DL = 8) or 486
  220.             MOV     EBX, ESP             ; save current stackpointer to align it
  221.             AND     ESP, 0FFFFFFFCh      ; align stack to avoid AC fault
  222.             PUSHFD                       ; save EFLAGS
  223.             POP     EAX                  ; get EFLAGS from stack
  224.             MOV     ECX, EAX             ; original value of EFLAGS
  225.             XOR     EAX, 40000H          ; toggle AC bit in EFLAGS
  226.             PUSH    EAX                  ; copy new value
  227.             POPFD                        ;  to EFLAGS
  228.             PUSHFD                       ; get new EFLAGS value
  229.             POP     EAX                  ; put into EAX
  230.             XOR     EAX, ECX             ; test if AC bit could be changed
  231.             PUSH    ECX                  ; restore original
  232.             POPFD                        ;  value of EFLAGS
  233.             MOV     ESP, EBX             ; restore original stack pointer
  234.             OR      EAX, EAX             ; EAX = 0 on 386, 40000h on 486
  235.             JNZS    $486_486dlc          ; if <> 0, must be 486/486dlc/486slc
  236. $chk_38600: PUSH    DX                   ; save CPU code
  237.             MOV     ESI, 32              ; 32 trials to check for POPAD bug
  238.             MOV     EAX, 12345678        ; load some value
  239. $trial_loop:MOV     EBX, EAX             ; save value for comparison
  240.             MOV     EDX, 0               ; prepare index and
  241.             MOV     EDI, 0               ;  base register to point to DS:0
  242.             PUSHAD                       ; push all 32-bit registers
  243.             POPAD                        ; pop all 32-bit registers
  244.             MOV     ECX, [EDX+EDI]       ; mem access changes EAX (POPAD bug!)
  245.             CMP     EAX, EBX             ; EAX changed ?
  246.             JNZS    $changed             ; EAX changed -> bug in AMD/Intel 386
  247.             ROL     EAX, 1               ; try next number
  248.             DEC     ESI                  ; decrement trial counter
  249.             JNZS    $trial_loop          ; until 32 trials thru, exits with Z=1
  250. $changed:   POP     DX                   ; restore CPU code
  251.             JNZS    $copro_test          ; EAX changed, must be Intel/AMD 386
  252.             MOV     DL, cpu_ct38600      ; C&T 38600 doesn't have that bug
  253.             JMPS    $copro_test          ; now test for coprocessor
  254. $486_486dlc:MOV     AX, 0FFFFh           ; load initial multiplicand
  255.             MOV     BX, 0FFFFh           ; load multiplicator
  256.             STRT_TIM                     ; start timer 2
  257.             REPT    30                   ; 486: MUL takes 26, AAM 15 clocks
  258.             MUL     BX                   ; execute 30 MULs
  259.             ENDM                         ; 486DLC: MUL takes 3, AAM 17 clocks
  260.             STOP_TIM                     ; elapsed time of timer 2 in BX
  261.             SHL     BX, 3                ; time for 240 MULs
  262.             CMP     BX, [AAMTime]        ; time for 240 MULs>time for 200 AAMs ?
  263.             MOV     DL, cpu_i486         ; default: it's a 486 (CPU = 15)
  264.             JAS     $ndp_test            ; yes, 486 has slow MUL
  265.             ADD     BX, BX               ; time for 480 MULs
  266.             CMP     BX, [AAMTime]        ; time for 480 MULs>time for 200 AAMs ?
  267.             JAS     $pentium             ; yes, Pentium MUL takes 11 clocks
  268.             MOV     DL, cpu_486dlc       ; no, fast MUL -> 486DLC/486SLC
  269.             JMPS    $ndp_test            ; continue with NDP test
  270. $pentium:   MOV     DL, cpu_pentium      ; speed of Pentium between 486DLC..486
  271. $ndp_test:  XOR     DH, DH               ; assume no coprocessor
  272.             XOR     AX, AX               ; clear register
  273.             OUT     0F0h, AL             ; clear error signal of coprocessor
  274.             FNINIT                       ; initialize coprocessor
  275.             MOV     [Ctrl], AX           ; clear status variable
  276.             NOT     AX                   ; load all 1's
  277.             MOV     [Stat], AX           ; initialize status variable to all 1's
  278.             FNSTCW  [Ctrl]               ; store NDP control word
  279.             MOV     AX, [Ctrl]           ; get control word
  280.             AND     AX, 0F3Fh            ; extract RC, PC and exception masks
  281.             CMP     AX, 033Fh            ; RC=0, PC=3, masks=3F ?
  282.             JNES    $chk_486sx           ; no -> no coprocessor present
  283.             FNSTSW  [Stat]               ; store NDP status
  284.             TEST    WORD PTR [Stat],383Fh; stack top & exceptions must be clear
  285.             JNZS    $chk_486sx           ; ST & exceptions not clear -> no NDP
  286.             MOV     DH, ndp_Emul         ; coprocessor is at least emulator (=1)
  287.             CMP     DL, cpu_i286         ; is CPU 80286 or higher ?
  288.             JBS     $no_emulat           ; no, emulation impossible
  289.             SMSW    AX                   ; get machine status word
  290.             TEST    AL, 4                ; test if EM bit of MSW set
  291.             JZS     $no_emulat           ; not set -> no NDP emulation
  292. $chk_486sx: CMP     DL, cpu_i486         ; CPU = Intel 486 and no/emulated copro ?
  293.             SBB     DL, -1               ; yes, CPU is 486sx (increment DL)
  294.             JMP     $ndp_exit            ; no further NDP checking
  295. $no_emulat: MOV     DH, ndp_i8087        ; coprocessor is at least 8087 (=2)
  296.             FLD1                         ; load 1.0
  297.             WAIT                         ; needed for 8087
  298.             FLDZ                         ; load 0.0
  299.             WAIT                         ; needed for 8087
  300.             FDIV                         ; 1.0 / 0.0 = +infinity
  301.             WAIT                         ; needed for 8087
  302.             FLD     ST(0)                ; duplicate +infinity
  303.             WAIT                         ; needed for 8087
  304.             FCHS                         ; generate -infinity
  305.             WAIT                         ; needed for 8087
  306.             FCOMPP                       ; compare infinities and clear NDP stk
  307.             WAIT                         ; needed for 8087
  308.             FSTSW   WORD PTR [Stat]      ; save condition codes
  309.             MOV     AX, [Stat]           ; load condition codes
  310.             SAHF                         ; transfer into CPU flags
  311.             JNES    $187_387             ; 187, C287 or 387 if numbers not equal
  312.             CMP     DL, cpu_i286         ; is CPU >= 286 ?
  313.             JBS     $ndp_exit1           ; no, coprocessor is 8087
  314.             MOV     DH, ndp_i80287       ; coprocessor is 287
  315.             JMPS    $chk_iit             ; check for IIT coprocessors
  316. $187_387:   CMP     DL, cpu_i286         ; is CPU >= 286 ?
  317.             JAES    $C287_387            ; yes, NDP is either C287, 287XL or 387
  318.             MOV     DH, ndp_i80C187      ; coprocessor is 187
  319.             JMPS    $ndp_exit1           ; store CPU and NDP code
  320. $C287_387:  CMP     DL, cpu_i386         ; is CPU >= 386 ?
  321.             JAES    $387_486             ; yes, NDP is 387 or 387sx, 486
  322.             MOV     DH, ndp_i287XL       ; coprocessor is C287
  323.             JMPS    $chk_iit             ; check for IIT coprocessors
  324. $387_486:   CMP     DL, cpu_i486         ; is CPU >= 486 ?
  325.             JAES    $i486                ; yes, NDP is 486 / 487
  326.             MOV     DH, ndp_i387         ; coprocessor is 387 or 387sx
  327.             JMPS    $chk_iit             ; check for IIT coprocessors
  328. $i486:      CMP     DL, cpu_pentium      ; is CPU Intel Pentium ?
  329.             JES     $ipentium            ; yes, FPU is also Pentium
  330.             MOV     DH, ndp_i486         ; NDP = 486 / 487
  331.             JMP     $ndp_exit            ; done with FPU detection
  332. $ipentium:  MOV     DH, ndp_pentium      ; set FPU type = Pentium
  333. $ndp_exit1: JMP     $ndp_exit            ; no further tests required
  334. $chk_iit:   FNINIT                       ; initialize coprocessor
  335.             FLD     CS:[$denormal]       ; load denormal number
  336.             FADD    ST(0), ST            ; result is zero on IIT
  337.             FNSTSW  AX                   ; get status of NDP into AX
  338.             TEST    AL, 02h              ; test if denormal exception flag set
  339.             JNZS    $chk_ulsi            ; Intel NDPs signal denormal exception
  340.             ADD     DH,ndp_2c87-ndp_i80287;set IIT coprocessor types
  341.             JMPS    $ndp_exit1           ; coprocessor type found
  342. $chk_ulsi:  CMP     DL, cpu_i386         ; CPU >= 386 ?
  343.             JBS     $chk_cyrix1          ; no, can not be ULSI
  344.             FNINIT                       ; initialize coprocessor
  345.             FLDCW   CS:[$53bit_prec]     ; PC => 53 bits (ULSI ignores PC)
  346.             FLD     TBYTE PTR CS:[$op1]  ; load 2-epsilon
  347.             FLD1                         ; load 1
  348.             FADDP   ST(1), ST            ; result should be 3 and PE raised
  349.             FSTP    TBYTE PTR [GDT]      ; store result, clear NDP stack
  350.             FNSTSW  AX                   ; get coprocessor status word
  351.             TEST    AL, 20h              ; precision exception ?
  352.             JNZS    $chk_cyrix1          ; ULSI computes 64 bit result, no PE!
  353.             FWAIT                        ; make sure result is stored
  354.             CMP     BYTE PTR [GDT], 0F8h ; check least significant mantissa bits
  355.             JNES    $chk_cyrix1          ; not expected result for ULSI
  356.             CMP     BYTE PTR [GDT+9], 40h; check exponent hi-byte
  357.             JNES    $chk_cyrix1          ; not expected result for ULSI
  358.             ADD     DH,ndp_83C87-ndp_i387; set ULSI types
  359.             JMPS    $ndp_exit1           ; done
  360. $chk_cyrix1:FNINIT                       ; initialize coprocessor
  361.             FLD     TBYTE PTR CS:[$nan]  ; load positive NaN
  362.             FLD     ST(0)                ; duplicate NaN
  363.             FCHS                         ; make negative NaN
  364.             FPATAN                       ; ATAN (-NaN, +NaN) should return +NaN
  365.             FSTP    TBYTE PTR [GDT]      ; store result, clear NDP stack
  366.             FWAIT                        ; wait until result is stored
  367.             CMP     BYTE PTR [GDT+9], 7Fh; Cyrix ret. +NAN (7F),Intel -NAN (FF)
  368.             JNES    $chk_ct              ; Intel coprocessor
  369. $chk_emc87: FNSTCW  [Ctrl]               ; store control word
  370.             OR      BYTE PTR [Ctrl+1],80h; set msb of control word
  371.             FLDCW   [Ctrl]               ; and load back into coprocessor
  372.             FSTCW   [Ctrl]               ; store control word again
  373.             FWAIT                        ; wait until stored
  374.             TEST    BYTE PTR [Ctrl+1],80h; could msb be set ?
  375.             JZS     $no_emc              ; no -> no EMC87
  376.             MOV     DH, ndp_emc87        ; set NDP type to EMC87
  377.             JMPS    $ndp_exit            ; done
  378. $no_emc:    ADD     DH,ndp_82S87-ndp_i80287; set old Cyrix types
  379.             FLD1                         ; load 1.0
  380.             FLD     ST(0)                ; load another 1.0
  381.             FYL2XP1                      ; compute 1.0*ld(2.0)
  382.             FLD1                         ; compare result with 1.0
  383.             FCOMPP                       ; new Cyrix copros have correct result
  384.             FNSTSW  AX                   ; store coprocessor condition bits
  385.             SAHF                         ; transfer to CPU flags
  386.             JNES    $ndp_exit            ; if incorrect result, not new Cyrix
  387.             ADD     DH,ndp_82S87p-ndp_82S87; set NDP-type to new Cyrix types
  388.             JMPS    $ndp_exit            ; done
  389. $chk_ct:    CMP     DL, cpu_i386         ; CPU >= 386 ?
  390.             JBS     $chk_387DX           ; no, can not be C&T
  391.             FNINIT                       ; initialize coprocessor
  392.             FLDPI                        ; load pi
  393.             F2XM1                        ; 2**(pi)-1=pi/2, argument out of range
  394.             FLD1                         ; load 1.0
  395.             FCHS                         ; -1.0
  396.             FLDPI                        ; load pi
  397.             FSCALE                       ; pi/2
  398.             FSTP    ST(1)                ; pi/2
  399.             FCOMPP                       ; 2**(pi)-1=pi/2 ?
  400.             FSTSW   AX                   ; save condition codes
  401.             SAHF                         ; transfer to CPU flags
  402.             JNES    $chk_387DX           ; not equal, not C&T
  403.             ADD     DH,ndp_38700-ndp_i387; set C&T types
  404.             JMPS    $ndp_exit            ; done
  405. $chk_387DX: CMP     DH, ndp_i387         ; Intel 387 ?
  406.             JNES    $ndp_exit            ; no, done. Only want to check i387
  407.             FNINIT                       ; initialize coprocessor
  408.             FLD1                         ; load 1.0
  409.             FCHS                         ; -1.0
  410.             FXTRACT                      ; split into mantissa and exponent(0)
  411.             FSTP    ST(0)                ; pop mantissa
  412.             FXAM                         ; look at sign of exponent
  413.             FNSTSW  AX                   ; store status word
  414.             AND     AH, 2                ; C1 set (negative) on old 387
  415.             FSTP    ST(0)                ; clear coprocessor stack
  416.             JNZS    $ndp_exit            ; C1 set, no 387DX
  417.             MOV     DH, ndp_i387DX       ; set NDP-type to 387DX
  418.             FNINIT                       ; initialize coprocessor
  419.             FBSTP   TBYTE PTR [GDT]      ; store BCD indefinite
  420.             CMP     BYTE PTR [GDT+7],0C0h; RapidCAD stores C0h, 387DX stores 80h
  421.             JNES    $ndp_exit            ; no RapidCAD
  422.             MOV     DX, ndp_RapidCAD*100H+cpu_RapidCAD; RapidCAD (NDP=21,CPU=14)
  423. $ndp_exit:  LDS     SI, ResultPtr        ; pointer to result record
  424.             MOV     [SI], DX             ; save CPU and NDP types
  425.             JMPS    $moveeven            ; skip over test data for NDP check
  426.  
  427. $denormal   DT      1
  428. $nan        DB      0FFh, 0FFh, 0FFh, 0FFh, 0FFh, 0FFh, 0FFh, 0FFh, 0FFh, 07Fh
  429. $op1        DB      0F0h, 0FFh, 0FFh, 0FFh, 0FFh, 0FFh, 0FFh, 0FFh, 0FFh, 03Fh
  430. $53bit_prec DW      027Fh
  431.  
  432.  
  433. $moveeven:  CMP     WORD PTR Debug_Flag,0; debugging output desired ?
  434.             JNZS    $moveeven1           ; no
  435.             MOV     AH, 9                ; #9, print string
  436.             PUSH    CS                   ; load
  437.             POP     DS                   ;  address of
  438.             MOV     DX, OFFSET CS:$dbg3  ;   debugging message
  439.             INT     21h                  ; call DOS, print debugging message
  440.             JMPS    $moveeven1           ; skip message text
  441. $dbg3       DB      'About to perform MOVEEVEN memory speed test', 0Dh, 0Ah ,'$'
  442.  
  443. $moveeven1: MOV     AX, DS               ; set up segment registers
  444.             MOV     ES, AX               ;  for memory move
  445.             XOR     SI, SI               ; offset in both segments
  446.             MOV     DI, SI               ;  is zero
  447.             MOV     CX, 5000             ; move 5000
  448.             REP     MOVSW                ;  words
  449.             STRT_TIM                     ; start timer 2
  450.             XOR     SI, SI               ; offset in both segments
  451.             MOV     DI, SI               ;  is zero
  452.             MOV     CX, 5000             ; move 5000
  453.             REP     MOVSW                ;  words
  454.             STOP_TIM                     ; elapsed time of timer 2 in BX
  455.             LDS     SI, ResultPtr        ; pointer to result record
  456.             MOV     [SI+6], BX           ; save MoveEvenTime
  457.  
  458.  
  459. $movebyte:  CMP     WORD PTR Debug_Flag,0; debugging output desired ?
  460.             JNZS    $movebyte1           ; no
  461.             MOV     AH, 9                ; #9, print string
  462.             PUSH    CS                   ; load
  463.             POP     DS                   ;  address of
  464.             MOV     DX, OFFSET CS:$dbg5  ;   debugging message
  465.             INT     21h                  ; call DOS, print debugging message
  466.             JMPS    $movebyte1           ; skip message text
  467. $dbg5       DB      'About to perform MOVEBYTE wait state test', 0Dh, 0Ah ,'$'
  468.  
  469. $movebyte1: MOV     AX, DS               ; set up segment registers
  470.             MOV     ES, AX               ;  for memory move
  471.             MOV     SI, 1                ; offset in source and destination
  472.             MOV     DI, SI               ;  segment is odd
  473.             STRT_TIM                     ; start timer 2
  474.             MOV     CX, 5000             ; move 5000
  475.             REP     MOVSB                ;  bytes
  476.             STOP_TIM                     ; elapsed time of timer 2 in BX
  477.             LDS     SI, ResultPtr        ; pointer to result struct
  478.             MOV     [SI+10], BX          ; save MoveByteTime
  479.  
  480. $movedouble:CMP     WORD PTR Debug_Flag,0; debugging output desired ?
  481.             JNZS    $movedoubl1          ; no
  482.             MOV     AH, 9                ; #9, print string
  483.             PUSH    CS                   ; load
  484.             POP     DS                   ;  address of
  485.             MOV     DX, OFFSET CS:$dbg6  ;   debugging message
  486.             INT     21h                  ; call DOS, print debugging message
  487.             JMPS    $movedoubl1          ; skip message text
  488. $dbg6       DB      'About to perform MOVEDOUBLE 386sx test', 0Dh, 0Ah ,'$'
  489.  
  490. $movedoubl1:LDS     SI, ResultPtr        ; pointer to result struct
  491.             CMP     BYTE PTR [SI],cpu_i386; CPU = iAPX 386 or i486 ?
  492.             JBS     $move_ems            ; no 386/486
  493.             MOV     AX, DS               ; load segment registers
  494.             MOV     ES, AX               ;  for memory move
  495.             XOR     SI, SI               ; offset in source and destination
  496.             MOV     DI, SI               ;  segment is 0
  497.             MOV     CX, 5000             ; move 5000
  498.             REP     MOVSD                ;  double words
  499.             STRT_TIM                     ; start timer 2
  500.             XOR     SI, SI               ; offset in source and destination
  501.             MOV     DI, SI               ;  segment is 0
  502.             MOV     CX, 5000             ; move 5000
  503.             REP     MOVSD                ;  double words
  504.             STOP_TIM                     ; elapsed time for 2 in BX
  505.             LDS     SI, ResultPtr        ; pointer to result struct
  506.             MOV     [SI+24], BX          ; save MoveDouble-Time
  507.  
  508. $chk_386sx: CMP     BYTE PTR [SI], cpu_i486 ; CPU >= i486 ?
  509.             JAES    $move_ems            ; yes, no need to test for 386sx
  510.             MOV     AX, [SI+6]           ; AX = MoveWord-Time
  511.  
  512.             XCHG    AX, BX               ; AX = MoveDouble-Time,BX=MoveWord-Time
  513.             SUB     AX, BX               ; MoveDTime - MoveWTime
  514.             ADD     AX, AX               ; 2 * (MoveDTime - MoveWTime)
  515.             CWD                          ; compute
  516.             XOR     AX, DX               ;  Abs (2 * (MoveDoubleTime -
  517.             SUB     AX, DX               ;   MoveWordTime))
  518.             CMP     BX, AX               ; Abs(2*(MoveDTime-MoveWTime))>MoveWTime ?
  519.             ADC     WORD PTR [SI], 0     ; CPU type = 386sx if true
  520.             CMP     BYTE PTR [SI],cpu_ct38600sx; CPU = C&T 38600sx ?
  521.             JNES    $move_ems            ; no
  522.             MOV     BYTE PTR [SI],cpu_i386sx; POPAD test unreliable for 386sx,
  523.                                          ; reset to Intel 386 since more likely
  524.  
  525. $move_ems:  CMP     WORD PTR Debug_Flag,0; debugging output desired ?
  526.             JNZS    $move_ems1           ; no
  527.             MOV     AH, 9                ; #9, print string
  528.             PUSH    CS                   ; load
  529.             POP     DS                   ;  address of
  530.             MOV     DX, OFFSET CS:$dbg7  ;   debugging message
  531.             INT     21h                  ; call DOS, print debugging message
  532.             JMPS    $move_ems1           ; skip message text
  533. $dbg7       DB      'About to perform EMS memory access test', 0Dh, 0Ah ,'$'
  534.  
  535. $move_ems1: CMP     BYTE PTR EMS_Flag, 0 ; does EMS memory exist ?
  536.             JES     $move_ext            ; no, skip this test
  537.             MOV     AH, 43h              ; #43, allocate page
  538.             MOV     BX, 1                ;  one page
  539.             INT     67h                  ; call EMM-driver (handle in DX)
  540.             MOV     AH, 47h              ; #47, save page map
  541.             INT     67h                  ; call EMM-driver
  542.             MOV     AH, 44h              ; #44, map page
  543.             MOV     AL, 0                ; physical page 0
  544.             MOV     BX, 0                ; logical page 0
  545.             INT     67h                  ; call EMM-driver
  546.             LES     DI, BufferPtr        ; pointer to buffer
  547.             MOV     CX, 5000             ; 5000 words
  548.             LDS     SI, ResultPtr        ; pointer to result struct
  549.             STRT_TIM                     ; start timer 2
  550.             CMP     BYTE PTR [SI], cpu_i386 ; processor 386 or higher?
  551.             LDS     SI, EMS_Base         ; pointer to EMS page frame
  552.             JAES    $is_386              ; is a 386/486
  553.             REP     MOVSW                ; move words from page frame to buffer
  554.             JMPS    $no_386              ; was no 386/486
  555. $is_386:    MOV     CX, 4000             ; 4000 double words = 1 EMS page
  556.             REP     MOVSD                ; move 4000 double words
  557. $no_386:    STOP_TIM                     ; elapsed time of timer 2 in BX
  558.             LDS     SI, ResultPtr        ; pointer to result struct
  559.             MOV     [SI+12], BX          ; save MoveEMSTime
  560.             MOV     AH, 48h              ; #48, restore map
  561.             INT     67h                  ; call EMM-driver
  562.             MOV     AH, 45h              ; #45, deallocate page
  563.             INT     67h                  ; call EMM-driver
  564.  
  565. $move_ext:  CMP     WORD PTR Debug_Flag,0; debugging output desired ?
  566.             JNZS    $move_ext1           ; no
  567.             MOV     AH, 9                ; #9, print string
  568.             PUSH    CS                   ; load
  569.             POP     DS                   ;  address of
  570.             MOV     DX, OFFSET CS:$dbg8  ;   debugging message
  571.             INT     21h                  ; call DOS, print debugging output
  572.             JMPS    $move_ext1           ; skip message text
  573. $dbg8       DB      'About to perform extended memory access test', 0Dh, 0Ah ,'$'
  574.  
  575. $move_ext1: CMP     BYTE PTR Ext_Flag, 0 ; does extended memory exist ?
  576.             JES     $screenfill          ; no, skip test
  577.             STRT_TIM                     ; start timer 2
  578.             XOR     AX, AX               ; load zero
  579.             MOV     BX, SS               ; load
  580.             MOV     ES, BX               ;  address
  581.             LEA     DI, GDT              ;   of GDT
  582.             MOV     CX, 30h              ; 30h bytes long
  583.             REP     STOSB                ; init with 0
  584.             LEA     SI, GDT              ; reload address of GDT
  585.             MOV     WORD PTR GDT+10H,10000; number of bytes to move
  586.             MOV     WORD PTR GDT+12H, 0  ; source:
  587.             MOV     BYTE PTR GDT+14H, 10H;  100000H (start of extended memory)
  588.             MOV     BYTE PTR GDT+15H, 93H; access rights (read/write)
  589.             MOV     WORD PTR GDT+18H,10000; number of bytes to move
  590.             LDS     DI, BufferPtr        ; load pointer to buffer
  591.             MOV     AX, DS               ; load pointer into DX:AX
  592.             XOR     DX, DX               ; linearize
  593.             SHL     AX, 1                ;  address,
  594.             RCL     DX, 1                ;   32 bit result
  595.             SHL     AX, 1                ;    in
  596.             RCL     DX, 1                ;     DX:AX
  597.             SHL     AX, 1                ;
  598.             RCL     DX, 1                ;
  599.             SHL     AX, 1                ;
  600.             RCL     DX, 1                ;
  601.             ADD     AX, DI               ;
  602.             ADC     DX, 0                ;
  603.             MOV     WORD PTR GDT+1AH, AX ; destination:
  604.             MOV     BYTE PTR GDT+1CH, DL ;  buffer
  605.             MOV     BYTE PTR GDT+1DH, 93H; access rights (read/write)
  606.             MOV     AH, 87h              ; move from extended memory
  607.             MOV     CX, 5000             ; move 5000 words from ext to buffer
  608.             INT     15H                  ; call AT-BIOS
  609.             STOP_TIM                     ; elapsed time of timer 2 in BX
  610.             LDS     SI, ResultPtr        ; pointer to result record
  611.             MOV     [SI+14], BX          ; save MoveExtTime
  612.  
  613. $screenfill:CMP     WORD PTR Debug_Flag,0; debugging output desired ?
  614.             JNZS    $screenfil1          ; no
  615.             MOV     AH, 9                ; #9, print string
  616.             PUSH    CS                   ; load
  617.             POP     DS                   ;  address of
  618.             MOV     DX, OFFSET CS:$dbg9  ;   debugging message
  619.             INT     21h                  ; call DOS, print string
  620.             JMPS    $screenfil1          ; skip message text
  621. $dbg9       DB      'About to perform SCREENFILL test', 0Dh, 0Ah ,'$'
  622.  
  623. $screenfil1:LES     DI, ScreenPtr        ; pointer to start of video memory
  624.             STRT_TIM                     ; start timer 2
  625.             MOV     CX, 5000             ; fill 5000 bytes
  626.             REP     STOSB                ;  of video memory
  627.             STOP_TIM                     ; elapsed time for timer 2 in BX
  628.             LDS     SI, ResultPtr        ; pointer to result struct
  629.             MOV     [SI+16], BX          ; save ScreenFillTime
  630.  
  631. $bios_write:CMP     WORD PTR Debug_Flag,0; debugging output desired ?
  632.             JNZS    $bios_writ1          ; no
  633.             MOV     AH, 9                ; #9, print string
  634.             PUSH    CS                   ; load
  635.             POP     DS                   ;  address of
  636.             MOV     DX, OFFSET CS:$dbg4  ;   debugging message
  637.             INT     21h                  ; call DOS, print debugging message
  638.             JMPS    $bios_writ1          ; skip message text
  639. $dbg4       DB      'About to perform BIOS_WRITE screen speed test', 0Dh, 0Ah ,'$'
  640.  
  641. $bios_writ1:STRT_TIM                     ; start timer 2
  642.             MOV     SI, 20               ; write 20 characters
  643. $out_loop:  MOV     AX, 0920h            ; #9, write char and attribute
  644.             MOV     BX, 0                ; page 0, attribute = blank
  645.             MOV     CX, 1                ; write one character at a time
  646.             INT     10H                  ; call video-BIOS
  647.             DEC     SI                   ; loop over number of chars
  648.             JNZS    $out_loop            ; until all 20 chars output
  649.             STOP_TIM                     ; elapsed time of timer 2 in BX
  650.             LDS     SI, ResultPtr        ; pointer to result struct
  651.             MOV     [SI+8], BX           ; save BIOS-WriteTime
  652.  
  653. $speed87:   CMP     WORD PTR Debug_Flag,0; debugging output desired ?
  654.             JNZS    $speed871            ; no
  655.             MOV     AH, 9                ; #9, print string
  656.             PUSH    CS                   ; load
  657.             POP     DS                   ;  address of
  658.             MOV     DX, OFFSET CS:$dbg10 ;   debugging message
  659.             INT     21h                  ; call DOS, print debugging message
  660.             JMPS    $speed871            ; skip message text
  661. $dbg10      DB      'About to perform NDP speed test', 0Dh, 0Ah ,'$'
  662.  
  663. $speed871:  LDS     SI, ResultPtr        ; pointer to result struct
  664.             CMP     BYTE PTR [SI+1], 1   ; real coprocessor present ?
  665.             JAS     $cont_87             ; yes, do coprocessor tests
  666.             JMP     $no_fpu              ; no, done
  667. $cont_87:   WAIT                         ; for 8087
  668.             FNINIT                       ; initialize coprocessor
  669.             WAIT                         ; for 8087
  670.             FLD1                         ; load 1
  671.             STRT_TIM                     ; start timer 2
  672.             REPT    40                   ; do following 40 times:
  673.             WAIT                         ;  needed on 8087
  674.             FSQRT                        ;  compute Sqrt(1)
  675.             ENDM
  676.             FWAIT                        ; wait until coprocessor done
  677.             STOP_TIM                     ; time for 40 sqrt computations on BX
  678.             LDS     SI, ResultPtr        ; pointer to result struct
  679.             MOV     [SI+20], BX          ; save 87-Time
  680.  
  681. $speed287:  FNINIT                       ; initialize coprocessor
  682.             FLD1                         ; load 1
  683.             STRT_TIM                     ; start timer 2
  684.             REPT    40                   ; do following 40 times:
  685.             NOP                          ;  needed on 8087
  686.             FSQRT                        ;  compute Sqrt(1)
  687.             ENDM
  688.             STOP_TIM                     ; time for 40 sqrt computations in BX
  689.             LDS     SI, ResultPtr        ; pointer to result struct
  690.             MOV     [i287Time], BX       ; save 287-Time
  691.             MOV     CX, [SI]             ; get CPU (CL) and NDP (CH)
  692. $chk_387sx: CMP     CL, cpu_i386sx       ; CPU = 80386sx ?
  693.             JES     $has_387sx           ; is SX
  694.             CMP     CL, cpu_ct38600sx    ; CPU = 38600sx ?
  695.             JES     $has_387sx           ; is SX
  696.             CMP     CL, cpu_486slc       ; CPU = 486SLC ?
  697.             JNES    $no_387sx            ; no SX
  698. $has_387sx: INC     CH                   ; set SX versions of 387 coprocessors
  699. $no_387sx:
  700. $store_type:MOV     [SI], CX             ; save CPU and NDP type
  701.             CMP     CL, cpu_i286         ; CPU higher than 286 ?
  702.             JBES    $no_weitek           ; no, Weitek only available for 386/486
  703.             PUSH    SI                   ; save pointer
  704.             PUSH    DS                   ;  to result struct
  705.             XOR     EAX, EAX             ; zero everything in result register
  706.             INT     11h                  ; do equipment check
  707.             TEST    EAX, 01000000h       ; check bit 24, set if Weitek present
  708.             POP     DS                   ; restore pointer
  709.             POP     SI                   ;  to result struct
  710.             JES     $no_weitek           ; bit not set, no Weitek
  711.             OR      BYTE PTR [SI+1], 80h ; set Weitek flag in coprocessor type
  712. $no_weitek: FNINIT                       ; reprogram
  713.             FLDCW   [SaveCtrl]           ;  original NDP control word
  714.  
  715. $no_fpu:    MOV     AL, [SystemStat]     ; get original system status
  716.             OUT     61h, AL              ;  and restore it
  717.  
  718. $ende:      POPF                         ; restore original flag settings
  719.             POP     DS                   ; restore Turbo Pascal's data segment
  720.             MOV     SP, BP               ; discard local variables
  721.             POP     BP                   ; restore caller's frame pointer
  722.             RET     22                   ; return, pop parameters
  723.  
  724. COMMENT #
  725.             MOV     EAX, 0417A000h       ; test if early 80386
  726.             MOV     ECX, 00000081h       ;  processor with 32 multiplication bug
  727.             MUL     ECX
  728.             CMP     EDX, 00000002h
  729.             JNZS    $mul_err
  730.             CMP     EAX, 0FE7A000h
  731.             JNZS    $mul_err
  732. #
  733.  
  734. SpeedTest   ENDP
  735.  
  736.  
  737. CODE        ENDS
  738.  
  739.             END
  740.